package com.gmail.yesguxun.tumblr.content;

import java.util.ArrayList;




import org.json.JSONArray;
import org.json.JSONObject;



import com.gmail.yesguxun.tumblr.Constant;
import com.gmail.yesguxun.tumblr.TrAccount;
import com.gmail.yesguxun.util.DeviceInfo;
import com.gmail.yesguxun.util.LogFactory;
import com.gmail.yesguxun.util.LogX;

import oauth.signpost.OAuth;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthProvider;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthNotAuthorizedException;
import oauth.signpost.http.HttpParameters;
import oauth.signpost.http.HttpRequest;
import oauth.signpost.http.HttpResponse;

public class TrContentProvider {
	
	static private TrContentProvider mProviderInstance;
	
	private LogX mLog = LogFactory.getLogObject();
	final String mLogTag = "provider";
	
	CommonsHttpOAuthConsumer mConsumer;
	CommonsHttpOAuthProvider mProvider;
	
	boolean mAuthorized = false;
	
	public static TrContentProvider getProviderInstance()
	{
		if(mProviderInstance == null)
		{
		    mProviderInstance = new TrContentProvider();
		}
		
		return mProviderInstance;
	}
	
	
	public boolean isAuthorized()
	{
	    return this.mAuthorized;
	}
	
	
	public boolean authorize()
	{
		TrAccount account = TrAccount.getTrAccount();
	    this.mAuthorized = false;
		
		if(!account.isAccountInfoValid())
		{
			mLog.debug("Invalid Account Information, Authorization Failed");
			return false;
		}
		
		String comsumerKey = Constant.APP_KEY_CONSUMER_PUBLIC;
		String consumerSecret = Constant.APP_KEY_CONSUMER_SECRET;
    	
    	this.mConsumer = new CommonsHttpOAuthConsumer(comsumerKey, consumerSecret);
		this.mProvider = new CommonsHttpOAuthProvider(null,  Constant.APP_URL_ACCESS_TOKEN, null);
		
		try{
			this.mProvider.retreieveAccessTokenXAuth(this.mConsumer, account.getEMail(), account.getPassword());
			this.mAuthorized = true;
		}
		catch(OAuthNotAuthorizedException e){
			mLog.debug(mLogTag, "Not Authorized: " + e.getResponseBody());	    		
    	}
    	catch(OAuthCommunicationException e)
    	{ 
    		mLog.debug(mLogTag, "Communication Problem");
    	}
    	catch(Exception e)
    	{
    		mLog.debug(mLogTag, "other exception " + e.getMessage());
    	}
    	
		return this.mAuthorized;
	}
	
	public ArrayList<TrContentObject> refreshData(int offset)
	{
		if(this.mAuthorized == false)
		{
			return null;
		}
		
		try{
		    
		    String viewMode = TrAccount.getTrAccount().getViewModeSelection();	    
            String responseContent =  getPhotoData(offset, viewMode);            
            ArrayList<TrContentObject> photoUrlList = getPhotoListFromResponse(responseContent,viewMode);
            
            return photoUrlList;
		}
		catch(OAuthNotAuthorizedException e){
			mLog.debug(mLogTag, "Not Authorized " + e.getResponseBody());	    		
    	}
    	catch(OAuthCommunicationException e)
    	{ 
    		mLog.debug(mLogTag, e.getResponseBody());
    	}
    	catch(Exception e)
    	{
    		mLog.debug(mLogTag, "other exception " + e.getMessage());
    	}
		
		return null;
	} 
	
	public ArrayList<TrContentObject> refreshData()
    {
        return refreshData(0);
    }
	
	
						
	
	private ArrayList<TrContentObject> getPhotoListFromResponse(String responseContent, String viewMode) throws Exception
	{
		ArrayList<TrContentObject> photoUriList = new ArrayList<TrContentObject>();
		JSONObject objResp = new JSONObject(responseContent);
		String postFieldName = "posts";
				
		if(viewMode.equals(Constant.ACCOUNT_PREFS_VIEW_MODE_VALUE_LIKE))
		{
		    postFieldName = "liked_posts";
		}		
        
        JSONArray objPosts = objResp.getJSONObject("response").getJSONArray(postFieldName);
        
        
        int numPosts = objPosts.length();
        mLog.info(mLogTag, "post number " + numPosts);          
        
        
        for(int indexPosts = 0;indexPosts < numPosts; indexPosts ++)
        {
        	JSONObject objPost = objPosts.getJSONObject(indexPosts);
        	JSONArray objPhotos = objPost.getJSONArray("photos");
        	String postId = objPost.getString("id");
        	String postType = objPost.getString("type");
        	String postReblogKey = objPost.getString("reblog_key");
        	
        	
        	//We only need post of photo type, now make sure of it
        	if((postType != null) && !postType.equals("photo"))
        	{
        		continue;
        	}
        	
        	int numPhotos = objPhotos.length();
        	for(int indexPhotos = 0;indexPhotos < numPhotos; indexPhotos ++)
        	{
        		String urlPhoto = selectPhoto(objPhotos.getJSONObject(indexPhotos));
        		mLog.debug(mLogTag, "Post:" + postId +  "url:" + urlPhoto);
        		
        		TrContentObject content = new TrContentObject(urlPhoto);
        		content.setProperty(Constant.CONTENT_PROPERTY_POST_ID, postId);
        		content.setProperty(Constant.CONTENT_PROPERTY_REBLOG_KEY, postReblogKey);
        		photoUriList.add(content);
        	}
          
        }
        
        return photoUriList;
	}
	
	private String selectPhoto(JSONObject objPhoto) throws Exception
	{
		//now only select the original_size;
		//return objPhoto.getJSONObject(Constant.API_JSON_PROPERTY_NAME_ORIG_SIZE).getString(Constant.API_JSON_PROPERTY_NAME_URL);
		
		int screenWidth = DeviceInfo.getScreenWidth();
		int screenHeight = DeviceInfo.getScreenHeight();
		
		String selectCriteria = TrAccount.getTrAccount().getSizeSelection();
		
        JSONObject sizeSelected = null;
        
        mLog.debug(mLogTag, "Screen resize " + screenWidth + "* " + screenHeight + " select:" + selectCriteria);
        
        if(selectCriteria.compareTo(Constant.ACCOUNT_PREFS_PIC_SIZE_VALUE_ORG) == 0)
        {
        	sizeSelected = objPhoto.getJSONObject(Constant.API_JSON_PROPERTY_NAME_ORIG_SIZE);
			mLog.debug(mLogTag, "Original Sized Pic is selected");
			return sizeSelected.getString(Constant.API_JSON_PROPERTY_NAME_URL);
        }
        		
		
		JSONArray altSizes = objPhoto.getJSONArray("alt_sizes");
		int altSizeLen = altSizes.length();
		
		//Try to find a size just a little big than the screen, 
		//From smaller to bigger
		//Todo: Stupid way, Can be optimized later
		for(int indexSizes = altSizeLen - 1; indexSizes >=0 ; indexSizes --)
		{
			JSONObject photoResized = altSizes.getJSONObject(indexSizes);
			int picWidth = photoResized.getInt("width");
			int picHeight = photoResized.getInt("height");
			
			mLog.debug(mLogTag, "the resized pic resolution is " + picWidth + "* " + picHeight);
			
			if(selectCriteria.compareTo(Constant.ACCOUNT_PREFS_PIC_SIZE_VALUE_BIG) == 0)
			{
				if( (picWidth >= screenHeight && picWidth >= screenWidth ) ||
					(picHeight >= screenHeight && picHeight >= screenWidth ) )
				{ 
					sizeSelected = photoResized;
					mLog.debug(mLogTag, "Alt Sized Pic is selected");
					break;
				}
			}
			else if(selectCriteria.compareTo(Constant.ACCOUNT_PREFS_PIC_SIZE_VALUE_MEDIA) == 0)
			{
				if( picWidth * picHeight > 800 * 400 )
				{ 
					sizeSelected = photoResized;
					mLog.debug(mLogTag, "Alt Sized Pic is selected");
					break;
				}
			}
			else if(selectCriteria.compareTo(Constant.ACCOUNT_PREFS_PIC_SIZE_VALUE_SMALL) == 0)
			{
				if( picWidth * picHeight > 400 * 200 )
				{ 
					sizeSelected = photoResized;
					mLog.debug(mLogTag, "Alt Sized Pic is selected");
					break;
				}
			}
		}
		
		if(sizeSelected == null)
		{
			sizeSelected = objPhoto.getJSONObject(Constant.API_JSON_PROPERTY_NAME_ORIG_SIZE);
			mLog.debug(mLogTag, "Original Sized Pic is selected");
		}
		
		mLog.debug(mLogTag, "Selected Pic Size: " + sizeSelected.getInt("width") + "* " + sizeSelected.getInt("height"));
		
		return sizeSelected.getString(Constant.API_JSON_PROPERTY_NAME_URL);
	}
	
	public boolean likeContent(TrContentObject content) 
    {	    	    
	    boolean result = false;
	    HttpRequest request = null;
        HttpParameters para = null;
        HttpResponse resp = null;
        int status = 0;
        
        try{
            request = this.mProvider.createRequestGet(Constant.API_URL_LIKE);
            para = new HttpParameters();
            para.put(Constant.API_PARAM_ID_NAME, content.getPropertyString(Constant.CONTENT_PROPERTY_POST_ID));        
            para.put(Constant.API_PARAM_REBLOG_KEY_NAME, content.getPropertyString(Constant.CONTENT_PROPERTY_REBLOG_KEY));
            
            this.mConsumer.signGet(request, para);
            resp = this.mProvider.sendRequest(request);
            status = resp.getStatusCode();              
        }
        catch(OAuthNotAuthorizedException e){
            mLog.debug(mLogTag, "Not Authorized " + e.getResponseBody());  
            result = false;
        }
        catch(OAuthCommunicationException e)
        { 
            mLog.debug(mLogTag, e.getResponseBody());            
        }
        catch(Exception e)
        {
            mLog.debug(mLogTag, "other exception " + e.getMessage());
        }
            
        if(status != 200)            
        {
            result = false;
        }    
        else
        {
            result = true;
        }
        
        mLog.debug("Liked the post of id:" + content.getPropertyString(Constant.CONTENT_PROPERTY_POST_ID) + " result:" + result);
        return result;
    }
	
	
	public String getPhotoData(int offset, String viewMode) throws Exception
    {
        HttpRequest request = null;
        HttpParameters para = null;
        if(viewMode.equals(Constant.ACCOUNT_PREFS_VIEW_MODE_VALUE_LIKE))
        {
            request = this.mProvider.createRequestGet(Constant.API_URL_LIKES);
            para = new HttpParameters();
            para.put(Constant.API_PARAM_LIMIT_NAME, Constant.API_PARAM_LIMIT_VALUE);        
            para.put(Constant.API_PARAM_OFFSET_NAME, Integer.toString(offset));            
        }
        else
        {       
            request = this.mProvider.createRequestGet(Constant.API_URL_DASH_BOARD);
            para = new HttpParameters();
            para.put(Constant.API_PARAM_LIMIT_NAME, Constant.API_PARAM_LIMIT_VALUE);
            para.put(Constant.API_PARAM_TYPE_NAME, Constant.API_PARAM_TYPE_VALUE);
            para.put(Constant.API_PARAM_OFFSET_NAME, Integer.toString(offset));
        }
        
        this.mConsumer.signGet(request, para);
        HttpResponse resp = this.mProvider.sendRequest(request);
        String responseContent =  OAuth.getStringFromStream(resp.getContent());     
        
        return responseContent;
    }
	
}
